How to Link a Zoho Projects Record to a Zoho CRM Deal Using Deluge

How to Link a Zoho Projects Record to a Zoho CRM Deal Using Deluge

Introduction

If you use both Zoho CRM and Zoho Projects, you already know the pain — a Deal gets closed or moves to a new stage, and then someone has to manually hop over to Projects, create a new project, fill in all the details, and somehow tie it back to the Deal. It works, but it is clunky and easy to forget.

What if that entire process just happened automatically the moment you needed it? That is exactly what we are going to set up here. In this post, I will walk you through how to use a Deluge script inside Zoho CRM to automatically create a project in Zoho Projects, map all the relevant Deal fields across, and then associate that project back to the Deal record — so everything stays connected in one place.

Let us get into it.


Why Bother Integrating Zoho Projects with Zoho CRM?

When a Deal progresses in CRM, your delivery or operations team often needs to start working immediately. Creating a project manually introduces a lag and risks details getting lost in translation — someone has to re-type the product dimensions, SKU count, packing notes, and more from the Deal into the new project.

By automating this with Deluge, you:

  • Eliminate manual data re-entry between two apps
  • Ensure every project carries the exact Deal data it needs from day one
  • Keep the CRM Deal updated with the new Project ID automatically
  • Give your team a clickable project link right from the Deal record

Step 1: Integrate Zoho Projects with Zoho CRM

Before any Deluge script can talk to Zoho Projects from CRM, you need to set up the official integration between the two apps. This is straightforward and only needs to be done once.

1 Inside Zoho CRM, click the Settings icon (⚙) in the top-right corner.
2 In the left panel, find and click on Marketplace, then choose Zoho from the options.
3 Scroll through the list and select Zoho Projects.
4 Click Set Up Now. Follow the on-screen prompts to authenticate and complete the integration.

Once that is done, Zoho Projects will appear as a related list section inside your CRM Deal records. That related list is exactly where the association link will show up later when the script runs.


Step 2: Understanding What the Deluge Script Does

Before I drop the code, let me quickly explain what is happening under the hood — because once you understand the logic, you will find it much easier to customise it for your own Deal fields.

The script does four things in sequence:

1
Fetches the Deal record from Zoho CRM using the Deal ID, pulling all the field values you need (deal name, dimensions, SKU count, dates, etc.)
2
Creates a new Project in Zoho Projects using the Projects API, passing the Deal data directly into the project's standard and custom fields (UDF fields)
3
Updates the Deal record in CRM with the newly generated Project ID so your team can reference it directly
4
Associates the project to the Deal via the integration's related list — so both records are visibly linked inside CRM

Step 3: The Deluge Script

Create a new Deluge custom function inside Zoho CRM (go to Settings → Functions → New Function) and paste the following code. I have added comments throughout so you know exactly what each block is responsible for.

// Fetch the Deal record from Zoho CRM using the Deal ID
getDeal = zoho.crm.getRecordById("Deals", Dealid);

// Pull the Deal Name to use as the Project name
project_name = ifnull(getDeal.get("Deal_Name"), "");

// Build the parameters map for the new Zoho Project
mp = Map();
mp.put("name", project_name);

// Set the project owner using their Zoho People User ID
mp.put("owner_zpuid", "205165000000032021");

// Project start date = today, end date = 3 days from today
mp.put("start_date", zoho.currentdate.toString("MM-dd-yyyy"));
mp.put("end_date", zoho.currentdate.addDay(3).toString("MM-dd-yyyy"));

// Map Deal custom fields to Zoho Projects UDF (User Defined Fields)
mp.put("UDF_CHAR1", ifnull(getDeal.get("Estimated_Target_BOM"), ""));
mp.put("UDF_CHAR2", ifnull(getDeal.get("Reason_for_change"), ""));
mp.put("UDF_LONG1", ifnull(getDeal.get("Maximum_no_of_SKU_s").toNumber(), ""));
mp.put("UDF_CHAR3", ifnull(getDeal.get("Current_packing_material"), ""));
mp.put("UDF_CHAR4", ifnull(getDeal.get("Box_Dimensions"), ""));
mp.put("UDF_CHAR5", ifnull(getDeal.get("Product_Dimensions"), ""));
mp.put("UDF_CHAR6", ifnull(getDeal.get("Projections"), ""));
mp.put("UDF_CHAR7", ifnull(getDeal.get("Customer_Interest_Level"), ""));

// Handle optional date field safely with a null check
if(!isNull(getDeal.get("Projection_Date")))
{
    mp.put("UDF_DATE1", ifnull(getDeal.get("Projection_Date").toString("MM-dd-yyyy"), ""));
    info getDeal.get("Projection_Date").toDate();
}

mp.put("UDF_CHAR8",  ifnull(getDeal.get("No_of_Stacks"), ""));
mp.put("UDF_CHAR9",  ifnull(getDeal.get("Projection_Term"), ""));
mp.put("UDF_CHAR10", ifnull(getDeal.get("Product_weight"), ""));
mp.put("UDF_CHAR11", ifnull(getDeal.get("Design_Project"), ""));
mp.put("UDF_CHAR12", ifnull(getDeal.get("Sample_available"), ""));
mp.put("UDF_CHAR13", ifnull(getDeal.get("Product_Model"), ""));
mp.put("UDF_CHAR14", ifnull(getDeal.get("Quality_Testing_Criteria").toList(","), ""));
mp.put("UDF_CHAR15", ifnull(getDeal.get("Product_Code"), ""));

// Handle numeric long field with a null check
if(!isNull(getDeal.get("Drop_Test_Height_mm")))
{
    mp.put("UDF_LONG2", ifnull(getDeal.get("Drop_Test_Height_mm").toLong(), ""));
}

// Attach the project template (replace with your own template ID)
mp.put("template_id", 205165000000096005);

// --- Create the Project via Zoho Projects REST API ---
portalname = "honecoredotcom";
portalID   = "60025983370";
projectsAPIEndPoint = "https://projectsapi.zoho.in/restapi";
url = projectsAPIEndPoint + "/portal/" + portalID + "/projects/";

resp = invokeurl
[
    url        : url
    type       : POST
    parameters : mp
    connection : "zcrm"
];

// Extract the new Project ID and Name from the API response
projectid = resp.getJSON("projects");
for each rec in projectid
{
    projid   = rec.get("id");
    projname = rec.get("name");
}

// --- Update the CRM Deal with the new Project ID ---
up_deal = zoho.crm.updateRecord(
    "Deals",
    Dealid.toLong(),
    {"Zoho_Project_ID": projid.toString()}
);
info up_deal;

// --- Associate the Project to the Deal via the integration related list ---
mp = Map();
mp.put("name", projname);
mp.put("Deals", Dealid);

datalist = List();
datalist.add(mp);

datamp = Map();
datamp.put("data", datalist);

resp_deal = invokeurl
[
    url        : "https://www.zohoapis.in/crm/v2/Deals/" + Dealid.toLong() + "/Zoho_Projects/" + projid.toString()
    type       : POST
    parameters : datamp.toString()
    connection : "z_projects"
];

info "Project Association Response: " + resp_deal;

Breaking Down the Key Parts

Let me walk through the sections that tend to trip people up.

UDF Fields — Zoho Projects Custom Fields

The UDF_CHAR, UDF_LONG, and UDF_DATE fields are the custom fields you have added to your Zoho Projects portal. Each one maps to a specific Deal field from CRM. If you have not created these custom fields in your Zoho Projects portal yet, go to Projects → Portal Settings → Custom Fields and add them before running the script. The field keys (like UDF_CHAR1) are assigned automatically in the order you create them.

The Two Connections — zcrm and z_projects

The script uses two separate API connections. zcrm is used to call the Zoho Projects API (it carries the OAuth token authorised for Projects). z_projects is used for the final association API call that links the project to the Deal in the CRM side. Make sure both connections exist under CRM Settings → Developer Hub → Connections before you trigger the function.

Portal ID and Owner ZPUID

The portalID is your Zoho Projects portal's unique numeric ID. You can find it in the URL when you are inside your Zoho Projects portal. Similarly, owner_zpuid is the Zoho People User ID of the person who should own the newly created project. Replace both values in the script with the ones from your own account.

Null Checks on Date and Long Fields

You will notice that Projection_Date and Drop_Test_Height_mm are wrapped in if(!isNull(...)) blocks. This is intentional. Calling .toString() or .toLong() on a null value in Deluge throws a runtime error. The null check skips those fields gracefully when the Deal record does not have a value set.


Where to Trigger This Function

You have a few options depending on how your team works:

  • Custom Button on the Deal: Add a button labeled "Create Project" to the Deal detail view. This gives your team full control over when the project gets created.
  • Workflow Rule: Trigger the function automatically when a Deal reaches a specific stage — for example, when the stage changes to "Won" or "Proposal Sent".
  • Blueprint Transition: If you use Zoho CRM Blueprints, you can fire the function as part of a stage transition action, ensuring it runs at exactly the right moment in your sales process.

What Happens After It Runs

✅ A new project is created in your Zoho Projects portal with all the Deal data already filled in

✅ The Deal record in CRM is updated with the new Zoho_Project_ID field value

✅ The project appears in the Zoho Projects related list section inside the Deal record

✅ Your operations or delivery team can jump straight to the project from the CRM Deal — no searching, no copy-pasting


Things You Will Want to Customise

This script is built around a specific set of Deal fields that may not match your CRM setup. Here is a quick checklist of what to check before you go live:

What to Check Where to Find It
portalID Zoho Projects URL when inside your portal
owner_zpuid Zoho People → Users → User profile URL
template_id Zoho Projects → Project Templates → URL of the template
UDF field keys (UDF_CHAR1, etc.) Zoho Projects → Portal Settings → Custom Fields
CRM Deal field API names CRM Settings → Modules and Fields → Deals → each field's API name
API connections (zcrm, z_projects) CRM Settings → Developer Hub → Connections

Common Issues and How to Fix Them

Problem Likely Cause Fix
Project is created but the Deal is not updated The Zoho_Project_ID field does not exist in the Deals module Add a Single Line custom field named Zoho_Project_ID to the Deals module first
API returns a 401 Unauthorized error The connection is missing the required OAuth scopes Re-authenticate the connection and add ZohoProjects.portals.READ and ZohoProjects.projects.CREATE scopes
Project is created but not visible in the Deal's related list The integration setup was not completed or the association API call failed Check the resp_deal response using info and confirm Step 1 (the marketplace integration) was completed
Null pointer error on date or number fields A required field in the Deal is empty Ensure all non-optional fields use ifnull() wrapping or an explicit null check

Final Thoughts

This kind of automation is genuinely one of those things that seems small until you are running 20 or 30 deals a month and realising how much time goes into that back-and-forth between CRM and Projects. Once this script is wired up properly, your team gets a project the moment one is needed — with all the right data already in it.

Take a few minutes to get your portal ID, owner ZPUID, and custom field mappings sorted before you run it the first time. Use info statements liberally during testing to see exactly what is coming back from each API call. Once you have it working on one Deal, you will want to trigger it everywhere.

If you run into something unexpected or want to extend this — say, automatically creating milestones or tasks inside the project based on Deal data — drop a comment below. Happy to help you take it further.

Post a Comment